/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ch.hslu.prg2.team2.logic;

import ch.hslu.prg2.team2.entity.Disc;
import ch.hslu.prg2.team2.entity.Player;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Claudio
 */
public class Gameboard implements INextMove, Serializable
{
    private ArrayList<ArrayList<Disc>> gameboard;
    private boolean running;
    private final int rows;
    private final int cols;
    private ComputerPlayer computerPlayer;
    private final Player player;
    private final GameboardAnalyzer gameboardAnalyzer;
    private transient ArrayList<IGameEndEvent> gameEndEventListeners = new ArrayList<>();
         
    public Gameboard(int rows, int cols, ComputerPlayer computerPlayer )
    {
        this.rows = rows;
        this.cols = cols;
        this.computerPlayer = computerPlayer;
        this.player = new Player("User");
        this.gameboardAnalyzer = new GameboardAnalyzer(this);
        this.running = true;
        
        initGameboard();       
    }
    
    public void setComputerPlayer( ComputerPlayer computerPlayer )
    {
        this.computerPlayer = computerPlayer;
    }
    
    public void playDisc( int col )
    {
        addDiscInternal( col, player);
        boolean humanHasWon = gameboardAnalyzer.hasPlayerWon(this.player);
        if( humanHasWon )
        {
            executeGameEndEvent(GameEndEventType.PlayerWon, col);
            return;
        }
        col = nextComputerDisc();
        boolean computerHasWon = gameboardAnalyzer.hasPlayerWon(this.computerPlayer);
        if( computerHasWon )
        {
            executeGameEndEvent(GameEndEventType.ComputerPlayerWon, col);
            return;
        }
        boolean gameIsFinished = gameboardAnalyzer.isGameFinished();
        if( gameIsFinished )
        {
            executeGameEndEvent(GameEndEventType.FieldFull, col);
            return;
        }
    }
    
    private int nextComputerDisc()
    {
        try
        {
            Thread.sleep(50);
        } 
        catch (InterruptedException ex)
        {
            Logger.getLogger(Gameboard.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        int col = computerPlayer.playNextDisc(this);
        addDiscInternal( col, computerPlayer);
        return col;
    }
    
    private void addDiscInternal(int col, Player player)
    {
        for(int i=rows-1; i >= 0; i-- )
        {
            if( gameboard.get(i).get(col) == null )
            {
                gameboard.get(i).set(col, new Disc(player));
                break;
            }
        }
    }
    
    public void registerGameEndEvents(IGameEndEvent listener)
    {
        if( gameEndEventListeners == null )
        {
            gameEndEventListeners = new ArrayList<>();
        }
        
        gameEndEventListeners.add(listener);
    }
    
    private void executeGameEndEvent(GameEndEventType type, int lastCol )
    {
        running = false;
        for( IGameEndEvent listener : gameEndEventListeners )
        {
            listener.gameEnded(type, lastCol);
        }
    }
    
    @Override
    public Disc getDisc( int row, int col )
    {
        return gameboard.get(row).get(col);
    }
    
    @Override
    public int getRowCount()
    {
        return rows;
    }
    
    @Override
    public int getColumnCount()
    {
        return cols;
    }
    
    public boolean isRunning()
    {
        return running;
    }
    
    public ComputerPlayer getComputerPlayer()
    {
        return computerPlayer;
    }
    
    @Override
    public boolean isColumnPlayable(int col)
    {
        return running && gameboard.get(0).get(col) == null;
    }
    
    private void initGameboard()
    {
        gameboard = new ArrayList<>();
        for( int i=0; i < rows; i++ )
        {
            ArrayList<Disc> column = new ArrayList<>();
            for( int j=0; j < cols; j++ )
            {
                column.add(null);
            }
            
            gameboard.add(column);
        }
    }
}
